package edu.jhu.tcj.purfuit;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 
 * @author Brad Gabrielse
 *
 */
public class Board {

	private final List<Space>[] edge = new List[4];
	private final List<Space>[] spokes = new List[4];
	private final Space centerSpace;
	
	private final List<Space> outsidePath = new ArrayList<Space>();
	private final List<Space>[] quarterPath = new List[4];
	private final List<Space>[] halfPath = new List[4];
	private final List<Space>[] figureEightPath = new List[4];

	/** Standard board 
	 * @param categories */
	public Board(Category[] categories) {
		centerSpace = new CenterSpace(0, categories);
		
		//Create the spaces
		for (int i = 0; i < 4; i++) {
			Space cornerSpace = Space.createCategorySpace((i*11+1), categories[(i+0)%4], true);
			Space categorySpace1 = Space.createCategorySpace((i*11+2), categories[(i+1)%4], false);
			Space rollAgainSpace1 = Space.createRollAgainSpace((i*11+3));
			Space categorySpace2 = Space.createCategorySpace((i*11+4), categories[(i+2)%4], false);
			Space categorySpace3 = Space.createCategorySpace((i*11+5), categories[(i+0)%4], false);
			Space categorySpace4 = Space.createCategorySpace((i*11+6), categories[(i+3)%4], false);
			Space rollAgainSpace2 = Space.createRollAgainSpace((i*11+7));
			Space categorySpace5 = Space.createCategorySpace((i*11+8), categories[(i+2)%4], false);
			
			edge[i] = new ArrayList<Space>(10);
			
			edge[i].add(cornerSpace);
			edge[i].add(categorySpace1);
			edge[i].add(rollAgainSpace1);
			edge[i].add(categorySpace2);
			edge[i].add(categorySpace3);
			edge[i].add(categorySpace4);
			edge[i].add(rollAgainSpace2);
			edge[i].add(categorySpace5);
			
			Space categorySpace6 = Space.createCategorySpace((i*11+9), categories[(i+1)%4], false);
			Space categorySpace7 = Space.createCategorySpace((i*11+10), categories[(i+2)%4], false);
			Space categorySpace8 = Space.createCategorySpace((i*11+11), categories[(i+3)%4], false);
			
			spokes[i] = new ArrayList<Space>();
			spokes[i].add(categorySpace6);
			spokes[i].add(categorySpace7);
			spokes[i].add(categorySpace8);
		}
		
		//Add the spaces to each potential path
		for (int i = 0; i < 4; i++) {
			quarterPath[i] = new ArrayList<Space>();
			quarterPath[i].add(edge[i].get(0));
			quarterPath[i].add(edge[i].get(1));
			quarterPath[i].add(edge[i].get(2));
			quarterPath[i].add(edge[i].get(3));
			quarterPath[i].add(edge[i].get(4));
			quarterPath[i].add(spokes[i].get(0));
			quarterPath[i].add(spokes[i].get(1));
			quarterPath[i].add(spokes[i].get(2));
			quarterPath[i].add(centerSpace);
			quarterPath[i].add(spokes[(i+3)%4].get(2));
			quarterPath[i].add(spokes[(i+3)%4].get(1));
			quarterPath[i].add(spokes[(i+3)%4].get(0));
			quarterPath[i].add(edge[(i+3)%4].get(4));
			quarterPath[i].add(edge[(i+3)%4].get(5));
			quarterPath[i].add(edge[(i+3)%4].get(6));
			quarterPath[i].add(edge[(i+3)%4].get(7));
			
			halfPath[i] = new ArrayList<Space>();
			halfPath[i].add(edge[i].get(0));
			halfPath[i].add(edge[i].get(1));
			halfPath[i].add(edge[i].get(2));
			halfPath[i].add(edge[i].get(3));
			halfPath[i].add(edge[i].get(4));
			halfPath[i].add(edge[i].get(5));
			halfPath[i].add(edge[i].get(6));
			halfPath[i].add(edge[i].get(7));
			halfPath[i].add(edge[(i+1)%4].get(0));
			halfPath[i].add(edge[(i+1)%4].get(1));
			halfPath[i].add(edge[(i+1)%4].get(2));
			halfPath[i].add(edge[(i+1)%4].get(3));
			halfPath[i].add(edge[(i+1)%4].get(4));
			halfPath[i].add(spokes[(i+1)%4].get(0));
			halfPath[i].add(spokes[(i+1)%4].get(1));
			halfPath[i].add(spokes[(i+1)%4].get(2));
			halfPath[i].add(centerSpace);
			halfPath[i].add(spokes[(i+3)%4].get(2));
			halfPath[i].add(spokes[(i+3)%4].get(1));
			halfPath[i].add(spokes[(i+3)%4].get(0));
			halfPath[i].add(edge[(i+3)%4].get(4));
			halfPath[i].add(edge[(i+3)%4].get(5));
			halfPath[i].add(edge[(i+3)%4].get(6));
			halfPath[i].add(edge[(i+3)%4].get(7));
			
			figureEightPath[i] = new ArrayList<Space>();
			figureEightPath[i].add(edge[i].get(0));
			figureEightPath[i].add(edge[i].get(1));
			figureEightPath[i].add(edge[i].get(2));
			figureEightPath[i].add(edge[i].get(3));
			figureEightPath[i].add(edge[i].get(4));
			figureEightPath[i].add(spokes[i].get(0));
			figureEightPath[i].add(spokes[i].get(1));
			figureEightPath[i].add(spokes[i].get(2));
			figureEightPath[i].add(centerSpace);
			figureEightPath[i].add(spokes[(i+3)%4].get(2));
			figureEightPath[i].add(spokes[(i+3)%4].get(1));
			figureEightPath[i].add(spokes[(i+3)%4].get(0));
			figureEightPath[i].add(edge[(i+3)%4].get(4));
			figureEightPath[i].add(edge[(i+3)%4].get(3));
			figureEightPath[i].add(edge[(i+3)%4].get(2));
			figureEightPath[i].add(edge[(i+3)%4].get(1));
			figureEightPath[i].add(edge[(i+3)%4].get(0));
			figureEightPath[i].add(edge[(i+2)%4].get(7));
			figureEightPath[i].add(edge[(i+2)%4].get(6));
			figureEightPath[i].add(edge[(i+2)%4].get(5));
			figureEightPath[i].add(edge[(i+2)%4].get(4));
			figureEightPath[i].add(spokes[(i+2)%4].get(0));
			figureEightPath[i].add(spokes[(i+2)%4].get(1));
			figureEightPath[i].add(spokes[(i+2)%4].get(2));
			figureEightPath[i].add(centerSpace);
			figureEightPath[i].add(spokes[(i+3)%4].get(2));
			figureEightPath[i].add(spokes[(i+3)%4].get(1));
			figureEightPath[i].add(spokes[(i+3)%4].get(0));
			figureEightPath[i].add(edge[(i+3)%4].get(4));
			figureEightPath[i].add(edge[(i+3)%4].get(5));
			figureEightPath[i].add(edge[(i+3)%4].get(6));
			figureEightPath[i].add(edge[(i+3)%4].get(7));
			
			outsidePath.add(edge[i].get(0));
			outsidePath.add(edge[i].get(1));
			outsidePath.add(edge[i].get(2));
			outsidePath.add(edge[i].get(3));
			outsidePath.add(edge[i].get(4));
			outsidePath.add(edge[i].get(5));
			outsidePath.add(edge[i].get(6));
			outsidePath.add(edge[i].get(7));
		}
	}
	
	public Collection<Space> getAvailableSpaces(Space space, int number) {
		List<Space> availSpaces = new ArrayList<Space>();
		
		int index = outsidePath.indexOf(space);
		if (index != -1) {
			int outsidePathSize = outsidePath.size();
			availSpaces.add(outsidePath.get((index-number+outsidePathSize) % outsidePathSize));
			availSpaces.add(outsidePath.get((index+number+outsidePathSize) % outsidePathSize));
		}
		
		for (int i = 0; i < 4; i++) {
			index = quarterPath[i].indexOf(space);
			if (index != -1) {
				int quarterPathSize = quarterPath[i].size();
				availSpaces.add(quarterPath[i].get((index-number+quarterPathSize) % quarterPathSize));
				availSpaces.add(quarterPath[i].get((index+number+quarterPathSize) % quarterPathSize));
			}
		}
		
		for (int i = 0; i < 4; i++) {
			index = halfPath[i].indexOf(space);
			if (index != -1) {
				int halfPathSize = halfPath[i].size();
				availSpaces.add(halfPath[i].get((index-number+halfPathSize) % halfPathSize));
				availSpaces.add(halfPath[i].get((index+number+halfPathSize) % halfPathSize));
			}
		}
		
		for (int i = 0; i < 4; i++) {
			index = figureEightPath[i].indexOf(space);
			if (index != -1) {
				int figureEightSize = figureEightPath[i].size();
				availSpaces.add(figureEightPath[i].get((index-number+figureEightSize) % figureEightSize));
				availSpaces.add(figureEightPath[i].get((index+number+figureEightSize) % figureEightSize));
			}
		}
		
		return availSpaces;
	}
	
	/**
	 * Removes a player from their current space and places them on the new space
	 * @param player to move
	 * @param space to add player to
	 */
	public void movePlayer(Player player, Space space) {
		player.setSpace(space);
	}
	
	/**
	 * Gets the edges of the board
	 * @return
	 */
	public Space[][] getEdges() {
		Space[][] edges = new Space[edge.length][];
		for (int i = 0; i < edge.length; i++) {
			edges[i] = edge[i].toArray(new Space[edge[i].size()]);
		}
		return edges;
	}
	
	/**
	 * Gets the spokes of the board
	 * @return
	 */
	public Space[][] getSpokes() {
		Space[][] spokes = new Space[this.spokes.length][];
		for (int i = 0; i < this.spokes.length; i++) {
			spokes[i] = this.spokes[i].toArray(new Space[this.spokes[i].size()]);
		}
		return spokes;
	}
	
	public Space getCenterSpace() {
		return centerSpace;
	}
	
}
